#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>

#define Normal_Driver_NUM          0
#define Normal_Driver_CNT			1		  	/* 设备号个数 */
#define Normal_Driver_NAME			"Normal_Driver"	/* 名字 */

typedef struct
{
	dev_t devid;			/* 设备号 	 */
	struct cdev cdev;		/* cdev 	*/
	struct class *class;		/* 类 		*/
	struct device *device;	/* 设备 	 */
	int major;				/* 主设备号	  */
	int minor;				/* 次设备号   */
    unsigned long long int Current_Offset;
}Normal_Driver_dev;

Normal_Driver_dev Normal_Driver;

static int Init_Normal_Driver(unsigned char EnableNotDisable)
{
    if(EnableNotDisable)
    {
        printk("Driver Init\n");
    }
    else
    {
        printk("Driver UnInit\n");
    }

    return 0;
}

static loff_t Normal_Driver_llseek(struct file *filp, loff_t offt,  int cnt)
{
    ((Normal_Driver_dev*)(filp->private_data))->Current_Offset = offt;
	return 0;
}

static int Normal_Driver_open(struct inode *inode, struct file *filp)
{
    Normal_Driver.Current_Offset=0;
	filp->private_data = &Normal_Driver; /* 设置私有数据 */
    printk("Driver Open\n");
	return 0;
}

static ssize_t Normal_Driver_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
    return 0;
}

static ssize_t Normal_Driver_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
    return 0;
}


/*
 * @description		: 关闭/释放设备
 * @param - filp 	: 要关闭的设备文件(文件描述符)
 * @return 			: 0 成功;其他 失败
 */
static int Normal_Driver_release(struct inode *inode, struct file *filp)
{
    printk("Driver Close\n");
	return 0;
}

/* 设备操作函数 */
static struct file_operations Normal_Driver_fops = {
	.owner = THIS_MODULE,
	.open = Normal_Driver_open,
	.read = Normal_Driver_read,
	.write = Normal_Driver_write,
	.release = 	Normal_Driver_release,
    .llseek = Normal_Driver_llseek,
};

static int __init Normal_Driver_init(void)
{
    int ret;

    if (Normal_Driver_NUM) 
    {		/*  定义了设备号 */
        Normal_Driver.major = Normal_Driver_NUM;
		Normal_Driver.devid = MKDEV(Normal_Driver.major, 0);
		ret = register_chrdev_region(Normal_Driver.devid, Normal_Driver_CNT, Normal_Driver_NAME);
		if(ret < 0) {
			pr_err("cannot register %s char driver [ret=%d]\n",Normal_Driver_NAME, Normal_Driver_CNT);
			return -EIO;
		}
	} 
    else 
    {						/* 没有定义设备号 */
		ret = alloc_chrdev_region(&Normal_Driver.devid, 0, Normal_Driver_CNT, Normal_Driver_NAME);	/* 申请设备号 */
        if(ret < 0) {
            pr_err("%s Couldn't alloc_chrdev_region, ret=%d\r\n", Normal_Driver_NAME, ret);
            return -EIO;
        }
        Normal_Driver.major = MAJOR(Normal_Driver.devid);	/* 获取分配号的主设备号 */
        Normal_Driver.minor = MINOR(Normal_Driver.devid);	/* 获取分配号的次设备号 */
	}
    
    Init_Normal_Driver(1);
    printk("Driver major=%d,minor=%d\r\n",Normal_Driver.major, Normal_Driver.minor);
    Normal_Driver.cdev.owner = THIS_MODULE;
    cdev_init(&Normal_Driver.cdev, &Normal_Driver_fops);

    ret = cdev_add(&Normal_Driver.cdev, Normal_Driver.devid, Normal_Driver_CNT);
	if(ret < 0)
    {
        Init_Normal_Driver(0);
		unregister_chrdev_region(Normal_Driver.devid, Normal_Driver_CNT);
        return -EIO;
    }

    Normal_Driver.class = class_create(THIS_MODULE, Normal_Driver_NAME);
	if (IS_ERR(Normal_Driver.class)) 
    {
        Init_Normal_Driver(0);
		cdev_del(&Normal_Driver.cdev);
        unregister_chrdev_region(Normal_Driver.devid, Normal_Driver_CNT);
        return -EIO;
	}

    Normal_Driver.device = device_create(Normal_Driver.class, NULL, Normal_Driver.devid, NULL, Normal_Driver_NAME);
	if (IS_ERR(Normal_Driver.device)) 
    {
        Init_Normal_Driver(0);
		class_destroy(Normal_Driver.class);
        cdev_del(&Normal_Driver.cdev);
        unregister_chrdev_region(Normal_Driver.devid, Normal_Driver_CNT);
        return -EIO;
	}

    return 0;
}

static void __exit Normal_Driver_exit(void)
{
    Init_Normal_Driver(0);
    cdev_del(&Normal_Driver.cdev);/*  删除cdev */
	unregister_chrdev_region(Normal_Driver.devid, Normal_Driver_CNT); /* 注销设备号 */
	device_destroy(Normal_Driver.class, Normal_Driver.devid);
	class_destroy(Normal_Driver.class);
}

module_init(Normal_Driver_init);
module_exit(Normal_Driver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("MIKE_ZHOU");
MODULE_INFO(intree, "Y");
